package com.dog.basics.common.util;

import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.StrUtil;

import java.util.Arrays;

/**
 * @description: 字节处理
 * @author: Guo
 * @create: 2020-01-04 20:16
 **/
public class ByteUtil {

	static final char[] HEX_DIGITS = "0123456789ABCDEF".toCharArray();


	/**
	 * 字节分组拆包
	 * @param bytes 字节数组
	 * @param size 按照多大拆
	 * @return
	 */
	public static byte[][] splitBytes(byte[] bytes, int size) {
		double splitLength = Double.parseDouble(size + "");
		int arrayLength = (int) Math.ceil(bytes.length / splitLength);
		byte[][] result = new byte[arrayLength][];
		int from, to;
		for (int i = 0; i < arrayLength; i++) {

			from = (int) (i * splitLength);
			to = (int) (from + splitLength);
			if (to > bytes.length)
				to = bytes.length;
			result[i] = Arrays.copyOfRange(bytes, from, to);
		}
		return result;
	}



	/**
	 *  JT809加解密
	 * @param M1
	 * @param IA1
	 * @param IC1
	 * @param key
	 * @param data
	 * @return
	 */
	public static byte[] encrypt(int M1,int IA1,int IC1,int key,byte [] data) {
		if(data == null) {
			return null;
		}
		//使用原对象，返回原对象
		byte[] array = data;
		//byte[] array = new byte[data.length]; //数组复制 返回新的对象
		//System.arraycopy(data, 0, array, 0, data.length);

		int idx=0;
		if(key==0){
			key=1;
		}
		int mkey = M1;
		if (0 == mkey )
		{
			mkey = 1;
		}
		while(idx<array.length){
			key = IA1 * ( key % mkey ) + IC1;
			array[idx]^=((key>>20)&0xFF);
			idx++;
		}
		return array;
	}

	public static void main(String[] args) {

		String a= "ABCCC";
		byte[] bytes = a.getBytes();
		System.out.println(bytesToHexString(bytes));
		byte[] encrypt = encrypt(10000000, 20000000, 30000000, 61010022, bytes);
		System.out.println(bytesToHexString(encrypt));
		byte[] encrypt1 = encrypt(10000000, 20000000, 30000000, 61010022, encrypt);
		System.out.println(bytesToHexString(encrypt1));
	}

	/**
	 * 从字节数组中删除前导0x00。
	 */
	public static byte[] stripLeadingNullBytes(byte[] input) {
		byte[] result = Arrays.copyOf(input, input.length);
		while (result.length > 0 && result[0] == 0x00) {
			result = Arrays.copyOfRange(result, 1, result.length);
		}
		return result;
	}

	/**
	 * 将字节数组转换为等效的十六进制字符串。 - 小写 （72deffff7f842e41）
	 */
	public static String toHexString(byte[] data) {
		char[] chars = new char[data.length * 2];
		for (int i = 0; i < data.length; i++) {
			chars[i * 2] = HEX_DIGITS[(data[i] >> 4) & 0xf];
			chars[i * 2 + 1] = HEX_DIGITS[data[i] & 0xf];
		}
		return new String(chars).toLowerCase();
	}

	/**
	 * 将字节数组转换为等效的十六进制字符串 - 大写并且美化 (72 DE FF FF 7F 84 2E 41 )
	 * @param bArr
	 * @return
	 */
	public static String bytesToHexString(byte[] bArr) {
		StringBuffer sb = new StringBuffer(bArr.length);
		String sTmp;
		for (int i = 0; i < bArr.length; i++) {
			sTmp = Integer.toHexString(0xFF & bArr[i]);
			if (sTmp.length() < 2) {
				sb.append(0);
			}
			sb.append(StrUtil.format("{} ", sTmp.toUpperCase()));
		}
		return sb.toString();
	}

	/**
	 * 将十六进制字符串转换为等效的字节数组。
	 */
	public static byte[] toByteArray(String data) {
		if (data == null) {
			return new byte[] {};
		}

		if (data.length() == 0) {
			return new byte[] {};
		}

		while (data.length() < 2) {
			data = "0" + data;
		}

		if (data.substring(0, 2).toLowerCase().equals("0x")) {
			data = data.substring(2);
		}
		if (data.length() % 2 == 1) {
			data = "0" + data;
		}

		data = data.toUpperCase();

		byte[] bytes = new byte[data.length() / 2];
		String hexString = new String(HEX_DIGITS);
		for (int i = 0; i < bytes.length; i++) {
			int byteConv = hexString.indexOf(data.charAt(i * 2)) * 0x10;
			byteConv += hexString.indexOf(data.charAt(i * 2 + 1));
			bytes[i] = (byte) (byteConv & 0xFF);
		}

		return bytes;
	}

	/**
	 * 反转字节数组的尾数。
	 *@param data 要翻转的数据字节数组
	 *@return 翻转阵法
	 */
	public static byte[] flipEndian(byte[] data) {
		if (data == null) {
			return new byte[0];
		}
		byte[] newData = new byte[data.length];
		for (int i = 0; i < data.length; i++) {
			newData[data.length - i - 1] = data[i];
		}

		return newData;
	}

	/**
	 * 用前导字节填充字节数组。
	 *@param data 需要填充的数据数据
	 *@param size 数据的最终所需大小。
	 *@param pad 填充要用于填充数据的字节值。
	 *@ 返回填充数组。
	 */
	public static byte[] leftPad(byte[] data, int size, byte pad) {
		if (size <= data.length) {
			return data;
		}

		byte[] newData = new byte[size];
		for (int i = 0; i < size; i++) {
			newData[i] = pad;
		}
		for (int i = 0; i < data.length; i++) {
			newData[size - i - 1] = data[data.length - i - 1];
		}

		return newData;
	}

	/**
	 *读取字节数组的一部分并将其作为自己的字节数组返回，这与子字符串没有什么不同。
	 *@param data 要读取的数据字节数组。
	 *@param start 所需数据的起始位置。
	 *@param size 数据大小。
	 *@ 返回包含所需数据的字节数组。
	 */
	public static byte[] readBytes(byte[] data, int start, int size) {
		if (data.length < start + size) {
			return new byte[0];
		}

		byte[] newData = Arrays.copyOfRange(data, start, start + size);

		return newData;
	}


	/**
	 *  double 转移 byte 字节
	 * @param d
	 * @return
	 */
	public static byte[] double2Bytes(double d) {
		long value = Double.doubleToRawLongBits(d);
		byte[] byteRet = new byte[8];
		for (int i = 0; i < 8; i++) {
			byteRet[i] = (byte) ((value >> 8 * i) & 0xff);
		}
		return byteRet;
	}

	/**
	 * byte[] 转 dobule
	 * @param arr
	 * @return
	 */
	public static double bytes2Double(byte[] arr) {
		long value = 0;
		for (int i = 0; i < 8; i++) {
			value |= ((long) (arr[i] & 0xff)) << (8 * i);
		}
		return Double.longBitsToDouble(value);
	}

	/**
	 * int到byte[] 由高位到低位
	 * @param i 需要转换为byte数组的整行值。
	 * @return byte数组
	 */
	public static byte[] intToByteArray(int i) {
		byte[] result = new byte[4];
		result[0] = (byte)((i >> 24) & 0xFF);
		result[1] = (byte)((i >> 16) & 0xFF);
		result[2] = (byte)((i >> 8) & 0xFF);
		result[3] = (byte)(i & 0xFF);
		return result;
	}

	/**
	 * byte[]转int
	 * @param bytes 需要转换成int的数组
	 * @return int值
	 */
	public static int byteArrayToInt(byte[] bytes) {
		int value=0;
		for(int i = 0; i < 4; i++) {
			int shift= (3-i) * 8;
			value +=(bytes[i] & 0xFF) << shift;
		}
		return value;
	}

	/**
	 * Long 转  byte
	 * @param num
	 * @return
	 */
	public static byte[] long2Bytes(long num) {
		byte[] byteNum = new byte[8];
		for (int ix = 0; ix < 8; ++ix) {
			int offset = 64 - (ix + 1) * 8;
			byteNum[ix] = (byte) ((num >> offset) & 0xff);
		}
		return byteNum;
	}

	/**
	 * byte转Long
	 * @param byteNum
	 * @return
	 */
	public static long bytes2Long(byte[] byteNum) {
		long num = 0;
		for (int ix = 0; ix < 8; ++ix) {
			num <<= 8;
			num |= (byteNum[ix] & 0xff);
		}
		return num;
	}

	/**
	 * Boolean转byte数组
	 * @param is
	 * @return
	 */
	public static byte[] booleanToArrayByte(Boolean is){
		byte[] result = new byte[1];
		result[0] = (byte) (Validator.isTrue(is)?0x00:0x01);
		return result;
	}

	/**
	 * byte数组转Boolean
	 * @param bytes
	 * @return
	 */
	public static Boolean arrayByteToBoolean(byte[] bytes){
		Boolean result = Boolean.FALSE;
		// 判断
		if (bytes.length>0){
			if (bytes[0] == (byte) 0x00){
				result = Boolean.TRUE;
			}
		}
		return result;
	}


	/**
	 * 浮点转换为字节
	 *
	 * @param f
	 * @return
	 */
	public static byte[] float2byte(float f) {

		// 把float转换为byte[]
		int fbit = Float.floatToIntBits(f);

		byte[] b = new byte[4];
		for (int i = 0; i < 4; i++) {
			b[i] = (byte) (fbit >> (24 - i * 8));
		}

		// 翻转数组
		int len = b.length;
		// 建立一个与源数组元素类型相同的数组
		byte[] dest = new byte[len];
		// 为了防止修改源数组，将源数组拷贝一份副本
		System.arraycopy(b, 0, dest, 0, len);
		byte temp;
		// 将顺位第i个与倒数第i个交换
		for (int i = 0; i < len / 2; ++i) {
			temp = dest[i];
			dest[i] = dest[len - i - 1];
			dest[len - i - 1] = temp;
		}

		return dest;

	}

	/**
	 * 字节转换为浮点
	 *
	 * @param b 字节（至少4个字节）
	 * @param index 开始位置
	 * @return
	 */
	public static float byte2float(byte[] b, int index) {
		int l;
		l = b[index + 0];
		l &= 0xff;
		l |= ((long) b[index + 1] << 8);
		l &= 0xffff;
		l |= ((long) b[index + 2] << 16);
		l &= 0xffffff;
		l |= ((long) b[index + 3] << 24);
		return Float.intBitsToFloat(l);
	}

		/**
         * 将长度为1的byte数组转换为32位int
         *
         * @param res
         *            byte[]
         * @return int
         * */
	public static int byte2int(byte[] res) {
		int targets = ByteUtil.byteArrayToInt(ByteUtil.leftPad(res, 4, (byte) 0x00));
		return targets;
	}
	/**
	 * Byte转Bit
	 */
	public static String byteToBit(byte b) {
		return "" +(byte)((b >> 7) & 0x1) +
				(byte)((b >> 6) & 0x1) +
				(byte)((b >> 5) & 0x1) +
				(byte)((b >> 4) & 0x1) +
				(byte)((b >> 3) & 0x1) +
				(byte)((b >> 2) & 0x1) +
				(byte)((b >> 1) & 0x1) +
				(byte)((b >> 0) & 0x1);
	}
	/**
	 * Bit转Byte
	 */
	public static byte BitToByte(String byteStr) {
		int re, len;
		if (null == byteStr) {
			return 0;
		}
		len = byteStr.length();
		if (len != 4 && len != 8) {
			return 0;
		}
		if (len == 8) {// 8 bit处理
			if (byteStr.charAt(0) == '0') {// 正数
				re = Integer.parseInt(byteStr, 2);
			} else {// 负数
				re = Integer.parseInt(byteStr, 2) - 256;
			}
		} else {//4 bit处理
			re = Integer.parseInt(byteStr, 2);
		}
		return (byte) re;
	}
}
